#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "Log.hpp"
#include "InetAddr.hpp"

using namespace std;

const static int defaultfd = -1;
const static int gbacklog = 16;

using task_t = function<void()>;
using func_t =function<string(const string &)>;///对应的是commandexcute中excute函数

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    LISTEN_ERROR,
    USAGE_ERROR
};

class TcpServer;
class ThreadData
{
public:
    ThreadData(int fd, InetAddr addr, TcpServer *s)
        : sockfd(fd), Clientaddr(addr), self(s)
    {
    }
    int sockfd;
    InetAddr Clientaddr;
    TcpServer *self;
};
class TcpServer
{
public:
    TcpServer(uint16_t port,func_t func) : _port(port), _listensock(defaultfd), _isrunning(false),_func(func)
    {
    }
    void InitServer()
    {
        // 1.创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0); // 与udpserver不同
        if (_listensock < 0)
        {

            Log(FATAL, "_listensock create error!");
            exit(SOCKET_ERROR);
        }
        Log(DEBUG, "listensock create success! listensock:%d", _listensock);
        // 进行绑定
        struct sockaddr_in addr;
        // 必须要初始化
        memset(&addr, 0, sizeof(addr));
        // 进行初始化在进行绑定
        addr.sin_port = htons(_port); // 将主机地址转化为网络地址
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_family = AF_INET;
        int n = ::bind(_listensock, (sockaddr *)&addr, sizeof(addr));
        if (n < 0)
        {
            Log(FATAL, "Bind Error");
            exit(BIND_ERROR);
        }
        Log(DEBUG, "bind success! listensock:%d", _listensock);
        // 3. tcp是面向连接的，所以通信之前，必须先建立连接。服务器是被连接的
        //    tcpserver 启动，未来首先要一直等待客户的连接到来
        n = ::listen(_listensock, gbacklog);
        if (n < 0)
        {
            Log(FATAL, "listen error");
            exit(LISTEN_ERROR);
        }
        Log(DEBUG, "listen success, sockfd is : %d", _listensock);
    }
    void Service(int sockfd, InetAddr client)
    {
        Log(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.ip().c_str(), client.port(), sockfd);
        string serveraddr = "[" + client.ip() + ":" + to_string(client.port()) + "] # ";
        // 执行
        while (1)
        {
            // 读消息
            char inbuffer[1024];
            int n = recv(sockfd, inbuffer, sizeof(inbuffer) - 1,0);
            if (n > 0) // success
            {
                inbuffer[n] = 0; // 消息所在地方
                cout << serveraddr << inbuffer << endl;
 
                string result=_func(inbuffer);
                send(sockfd, result.c_str(), result.size(),0); // 写入之后对面就会检测到进而进行下一步
            }
            else if (n == 0)
            {
                Log(INFO, "%s quit\n", serveraddr.c_str());
                break;
            }
            else
            {
                Log(ERROR, "read error!");
                break;
            }
        }
        // 打开就要关闭
        close(sockfd);
    }
    // 类类成员函数用static
    static void *HanderSock(void *args)
    {
        pthread_detach(pthread_self()); // 线程分离是实现多线程情况的一种方式之一
        ThreadData *td = static_cast<ThreadData *>(args);
        td->self->Service(td->sockfd, td->Clientaddr);
        delete td;
        return nullptr;
    }
    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 进行连接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = ::accept(_listensock, (struct sockaddr *)&peer, &len);
            if (sockfd < 0)
            {
                Log(WARNING, "accept error!  sockfd:%d", sockfd);
                sleep(1);
                continue;
            }
            Log(DEBUG, "accept success!");
            //多线程
            pthread_t t;
            ThreadData *td = new ThreadData(sockfd, InetAddr(peer), this);
            //禁止关闭文件描述符---->因为线程共享地址空间
            pthread_create(&t, nullptr, HanderSock, td); // 线程分离
        }
        _isrunning = false;
    }
    ~TcpServer()
    {
        if (_listensock > defaultfd)
        {
            close(_listensock); // 关闭文件描述符
        }
    }

private:
    uint16_t _port;
    int _listensock;
    bool _isrunning;
    func_t _func;
};